package cn.kent.base.notify;


/**
 * 演示notify和notifyAll方法的区别
 * notify是释放共享变量的监视器锁，并随机让一个线程去拿着个资源(随机唤醒)，但是这个线程仍然要先竞争这个资源的监视器锁，然后才能操作共享变量
 * notifyAll是释放共享变量的监视器锁，并唤醒所有在该共享变量上由于调用wait系列方法而被挂起的线程。
 */
public class NotifyAndNotifyAll {
    private static volatile Object resourceA = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("threadA get resource A lock");
                    synchronized (resourceA) {
                        System.out.println("threadA begin wait");
                        resourceA.wait();
                        System.out.println("threadA end wait");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("threadB get resource A lock");
                    synchronized (resourceA) {
                        System.out.println("threadB begin wait");
                        resourceA.wait();
                        System.out.println("threadB end wait");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread threadC = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resourceA) {
                    System.out.println("threadC begin notify");
                    // resourceA.notify();
                    resourceA.notifyAll(); // notifyAll方法只能唤醒在调用notifyAll方法之前加入到阻塞集合的线程。
                }
            }
        });

        // 启动线程
        threadA.start();
        threadB.start();
        Thread.sleep(1000); // 将AB线程全部执行到begin wait
        threadC.start(); // 让线程C去调用notify方法，唤醒了一个线程，从结果看，只有A线程被唤醒，B线程阻塞
        // 等待线程结束
        threadA.join();
        threadB.join();
        threadC.join();
        System.out.println("main over");
    }
}
